﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace ProgNetComponents.Hosting
{
    /// <summary>
    /// Host Property Descriptor
    /// </summary>
    public class HostPropertyDescriptor : PropertyDescriptor
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="HostPropertyDescriptor"/> class.
        /// </summary>
        /// <param name="property">The property.</param>
        public HostPropertyDescriptor(PropertyDescriptor property)
            : base(property)
        {
            tail = property;
        }
        /// <summary>
        /// Gets the component.
        /// </summary>
        /// <param name="component">The component.</param>
        /// <returns></returns>
        protected object GetComponent(object component)
        {
            IHostObject h = component as IHostObject;
            if (h != null)
                return h.HostObject;
            return component;
        }
        /// <summary>
        /// tail
        /// </summary>
        private readonly PropertyDescriptor tail;
        /// <summary>
        /// Gets the attributes.
        /// </summary>
        /// <param name="attribs">The attribs.</param>
        /// <returns></returns>
        static Attribute[] GetAttributes(AttributeCollection attribs)
        {
            var arr = new Attribute[attribs.Count];
            attribs.CopyTo(arr, 0);
            return arr;
        }

        /// <summary>
        /// Enables other objects to be notified when this property changes.
        /// </summary>
        /// <param name="component">The component to add the handler for.</param>
        /// <param name="handler">The delegate to add as a listener.</param>
        public override void AddValueChanged(object component, EventHandler handler)
        {
            tail.AddValueChanged(GetComponent(component), handler);
        }
        /// <summary>
        /// Enables other objects to be notified when this property changes.
        /// </summary>
        /// <param name="component">The component to remove the handler for.</param>
        /// <param name="handler">The delegate to remove as a listener.</param>
        public override void RemoveValueChanged(object component, EventHandler handler)
        {
            tail.RemoveValueChanged(GetComponent(component), handler);
        }
        /// <summary>
        /// When overridden in a derived class, returns whether resetting an object changes its value.
        /// </summary>
        /// <param name="component">The component to test for reset capability.</param>
        /// <returns>
        /// true if resetting the component changes its value; otherwise, false.
        /// </returns>
        public override bool CanResetValue(object component)
        {
            return tail.CanResetValue(GetComponent(component));
        }
        /// <summary>
        /// Gets the type converter for this property.
        /// </summary>
        /// <returns>A <see cref="T:System.ComponentModel.TypeConverter" /> that is used to convert the <see cref="T:System.Type" /> of this property.</returns>
        ///   <PermissionSet>
        ///   <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode" />
        ///   </PermissionSet>
        public override TypeConverter Converter
        {
            get { return tail.Converter; }
        }
        /// <summary>
        /// Gets the name of the category to which the member belongs, as specified in the <see cref="T:System.ComponentModel.CategoryAttribute" />.
        /// </summary>
        /// <returns>The name of the category to which the member belongs. If there is no <see cref="T:System.ComponentModel.CategoryAttribute" />, the category name is set to the default category, Misc.</returns>
        ///   <PermissionSet>
        ///   <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode, ControlEvidence" />
        ///   </PermissionSet>
        public override string Category
        {
            get { return tail.Category; }
        }
        /// <summary>
        /// When overridden in a derived class, gets the type of the component this property is bound to.
        /// </summary>
        /// <returns>A <see cref="T:System.Type" /> that represents the type of component this property is bound to. When the <see cref="M:System.ComponentModel.PropertyDescriptor.GetValue(System.Object)" /> or <see cref="M:System.ComponentModel.PropertyDescriptor.SetValue(System.Object,System.Object)" /> methods are invoked, the object specified might be an instance of this type.</returns>
        public override Type ComponentType
        {
            get { return tail.ComponentType; }
        }
        /// <summary>
        /// Gets the description of the member, as specified in the <see cref="T:System.ComponentModel.DescriptionAttribute" />.
        /// </summary>
        /// <returns>The description of the member. If there is no <see cref="T:System.ComponentModel.DescriptionAttribute" />, the property value is set to the default, which is an empty string ("").</returns>
        public override string Description
        {
            get { return tail.Description; }
        }
        /// <summary>
        /// Gets whether this member should be set only at design time, as specified in the <see cref="T:System.ComponentModel.DesignOnlyAttribute" />.
        /// </summary>
        /// <returns>true if this member should be set only at design time; false if the member can be set during run time.</returns>
        public override bool DesignTimeOnly
        {
            get { return tail.DesignTimeOnly; }
        }
        /// <summary>
        /// Gets the collection of attributes for this member.
        /// </summary>
        /// <returns>An <see cref="T:System.ComponentModel.AttributeCollection" /> that provides the attributes for this member, or an empty collection if there are no attributes in the <see cref="P:System.ComponentModel.MemberDescriptor.AttributeArray" />.</returns>
        public override AttributeCollection Attributes
        {
            get { return tail.Attributes; }
        }
        /// <summary>
        /// Gets the name that can be displayed in a window, such as a Properties window.
        /// </summary>
        /// <returns>The name to display for the member.</returns>
        public override string DisplayName
        {
            get { return tail.DisplayName; }
        }
        /// <summary>
        /// Returns a <see cref="T:System.ComponentModel.PropertyDescriptorCollection" /> for a given object using a specified array of attributes as a filter.
        /// </summary>
        /// <param name="instance">A component to get the properties for.</param>
        /// <param name="filter">An array of type <see cref="T:System.Attribute" /> to use as a filter.</param>
        /// <returns>
        /// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection" /> with the properties that match the specified attributes for the specified component.
        /// </returns>
        public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
        {
            return tail.GetChildProperties(GetComponent(instance), filter);
        }
        /// <summary>
        /// Gets an editor of the specified type.
        /// </summary>
        /// <param name="editorBaseType">The base type of editor, which is used to differentiate between multiple editors that a property supports.</param>
        /// <returns>
        /// An instance of the requested editor type, or null if an editor cannot be found.
        /// </returns>
        public override object GetEditor(Type editorBaseType)
        {
            return tail.GetEditor(editorBaseType);
        }
        /// <summary>
        /// When overridden in a derived class, gets the current value of the property on a component.
        /// </summary>
        /// <param name="component">The component with the property for which to retrieve the value.</param>
        /// <returns>
        /// The value of a property for a given component.
        /// </returns>
        public override object GetValue(object component)
        {
            return tail.GetValue(GetComponent(component));
        }
        /// <summary>
        /// When overridden in a derived class, sets the value of the component to a different value.
        /// </summary>
        /// <param name="component">The component with the property value that is to be set.</param>
        /// <param name="value">The new value.</param>
        public override void SetValue(object component, object value)
        {
            tail.SetValue(GetComponent(component), value);
        }
        /// <summary>
        /// Gets a value indicating whether the member is browsable, as specified in the <see cref="T:System.ComponentModel.BrowsableAttribute" />.
        /// </summary>
        /// <returns>true if the member is browsable; otherwise, false. If there is no <see cref="T:System.ComponentModel.BrowsableAttribute" />, the property value is set to the default, which is true.</returns>
        public override bool IsBrowsable
        {
            get { return tail.IsBrowsable; }
        }
        /// <summary>
        /// Gets a value indicating whether this property should be localized, as specified in the <see cref="T:System.ComponentModel.LocalizableAttribute" />.
        /// </summary>
        /// <returns>true if the member is marked with the <see cref="T:System.ComponentModel.LocalizableAttribute" /> set to true; otherwise, false.</returns>
        public override bool IsLocalizable
        {
            get { return tail.IsLocalizable; }
        }
        /// <summary>
        /// When overridden in a derived class, gets a value indicating whether this property is read-only.
        /// </summary>
        /// <returns>true if the property is read-only; otherwise, false.</returns>
        public override bool IsReadOnly
        {
            get { return tail.IsReadOnly; }
        }
        /// <summary>
        /// Gets the name of the member.
        /// </summary>
        /// <returns>The name of the member.</returns>
        public override string Name
        {
            get { return tail.Name; }
        }
        /// <summary>
        /// When overridden in a derived class, gets the type of the property.
        /// </summary>
        /// <returns>A <see cref="T:System.Type" /> that represents the type of the property.</returns>
        public override Type PropertyType
        {
            get { return tail.PropertyType; }
        }
        /// <summary>
        /// When overridden in a derived class, resets the value for this property of the component to the default value.
        /// </summary>
        /// <param name="component">The component with the property value that is to be reset to the default value.</param>
        public override void ResetValue(object component)
        {
            tail.ResetValue(GetComponent(component));
        }
        /// <summary>
        /// Gets a value indicating whether value change notifications for this property may originate from outside the property descriptor.
        /// </summary>
        /// <returns>true if value change notifications may originate from outside the property descriptor; otherwise, false.</returns>
        public override bool SupportsChangeEvents
        {
            get { return tail.SupportsChangeEvents; }
        }
        /// <summary>
        /// When overridden in a derived class, determines a value indicating whether the value of this property needs to be persisted.
        /// </summary>
        /// <param name="component">The component with the property to be examined for persistence.</param>
        /// <returns>
        /// true if the property should be persisted; otherwise, false.
        /// </returns>
        public override bool ShouldSerializeValue(object component)
        {
            return tail.ShouldSerializeValue(GetComponent(component));
        }
    }
   
}
